package com.xxjh.brs.map.service;

import com.xxjh.brs.map.enums.MapServiceType;
import com.xxjh.brs.map.utils.ProgressCalculation;
import com.xxjh.brs.map.vo.DownloadProgress;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.*;
import java.net.URL;
import java.nio.file.Files;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author CHENCHEN
 * @title 下载地图服务基础方法
 * @company 新兴际华科技（天津）有限公司
 * @create 2024-07-03 19:21
 */
@Slf4j
@Component
public class AbstractMapService {

    @Value("${spring.ftp.localdownloaddir}")
    protected String localDownloadDir;

    @Value("${spring.ftp.localDirectoryPath}")
    protected String localDirectoryPath;

    protected final ConcurrentHashMap<Long, DownloadProgress> taskProgressMap = new ConcurrentHashMap<>();

    /**
     * 获取范围下载进度信息。
     *
     * @param taskId      任务ID。
     * @return 下载进度信息。
     */
    protected DownloadProgress downloadProgress(long taskId) {
        DownloadProgress progress = taskProgressMap.get(taskId);
        ProgressCalculation.updateDownloadSpeed(progress);
        return progress;
    }

    /**
     * 下载远程文件并保存至本地。
     *
     * @param url      下载链接。
     * @param file     保存文件的目标路径。
     * @param returnBytes 是否需要返回下载的数据字节。
     * @return 如果returnBytes为true，则返回下载的数据字节，否则返回null。
     * @throws IOException 网络或IO异常。
     */
    protected byte[] download(URL url, File file, boolean returnBytes) throws IOException {
        Files.createDirectories(file.getParentFile().toPath());
        try (BufferedInputStream bis = new BufferedInputStream(url.openStream());
             BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file))) {
            byte[] buffer = new byte[1024]; // 减小缓冲区大小以减少内存占用
            int read;
            if (returnBytes) {
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                while ((read = bis.read(buffer)) != -1) {
                    bos.write(buffer, 0, read);
                    outputStream.write(buffer, 0, read);
                }
                return outputStream.toByteArray();
            } else {
                while ((read = bis.read(buffer)) != -1) {
                    bos.write(buffer, 0, read);
                }
                return null;
            }
        }
    }

    /**
     * 尝试下载指定URL的内容到指定路径，并在遇到IO异常时进行重试。
     *
     * @param urlStr 待下载文件的URL字符串。
     * @param path 下载内容保存的本地文件路径。
     * @param alias 下载地图类型。
     * @throws IOException 如果所有重试都失败，则抛出最后一个捕获到的IOException。
     */
    protected void downloadWithRetry(String urlStr, String path, String alias) throws IOException {
        int retryCount = 3; // 初始化重试计数
        while (retryCount > 0) {
            try {
                // 尝试下载文件
                download(new URL(urlStr), new File(path), false);
                break; // 如果下载成功，则跳出循环
            } catch (IOException e) {
                retryCount--; // 减少重试次数
                if (retryCount == 0) {
                    // 所有重试均失败，重新抛出最后一次捕获的异常
                    log.warn("Download failed, retrying > 3 (Attempt {}/{}) Error: {}", retryCount, urlStr, e.getMessage());
                }
            }
        }
    }

    /**
     * 根据别名生成瓦片路径
     *
     * @param alias 别名（如 "ttt" 或 "2d"）
     * @param x X坐标
     * @param y Y坐标
     * @param z 缩放级别
     * @return 地图请求的URL，如果找不到别名则返回null
     */
    protected String generateTilePathByAlias(String alias, int x, int y, int z) {
        return String.format(localDirectoryPath, alias, z, y, x);
    }

    protected String getUrlPath(String alias, int x, int y, int z){
        if(alias.equals(MapServiceType.MAP_3T)){
            return MapServiceType.THREE_T.getUrl(x, y, z);
        }else if(alias.equals(MapServiceType.MAP_2D)){
            return MapServiceType.TWO_D.getUrl(x, y, z);
        }
        return null;
    }
}
